/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.jdy.haoduoai.lyric;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 表示一首歌的歌词对象,它可以以某种方式来画自己
 * 
 * @author hadeslee
 */
public class Lyric implements Serializable {

  public List<Sentence> list = new ArrayList<Sentence>();// 里面装的是所有的句子

  private final boolean initDone;// 是否初始化完毕了
  private transient File file;// 该歌词所存在文件

  // 用于缓存的一个正则表达式对象
  private static final Pattern pattern = Pattern.compile("(?<=\\[).*?(?=\\])");

  public Lyric(File file) {
    this.file = file;
    init(file);
    initDone = true;
  }

  /**
   * 根据歌词内容和播放项构造一个 歌词对象
   * 
   * @param lyric
   *          歌词内容
   * @param info
   *          播放项
   */
  public Lyric(String lyric) {
    this.init(lyric);
    initDone = true;
  }

  /**
   * 得到此歌词保存的地方
   * 
   * @return 文件
   */
  public File getLyricFile() {
    return file;
  }

  /**
   * 根据文件来初始化
   * 
   * @param file
   *          文件
   */
  private void init(File file) {
    BufferedReader br = null;
    try {
      br = new BufferedReader(new InputStreamReader(new FileInputStream(file),
          "UTF-8"));
      StringBuilder sb = new StringBuilder();
      String temp = null;
      while ((temp = br.readLine()) != null) {

        sb.append(temp).append("\n");
      }
      init(sb.toString());
    } catch (Exception ex) {
      Logger.getLogger(Lyric.class.getName()).log(Level.SEVERE, null, ex);

    } finally {
      try {
        br.close();
      } catch (Exception ex) {
        Logger.getLogger(Lyric.class.getName()).log(Level.SEVERE, null, ex);
      }
    }
  }

  private void appendEndLine() {
    String content = new String("(完)");
    long endFromTime = list.get(list.size() - 1).getFromTime() + 2000;
    list.add(new Sentence(content, endFromTime));
  }

  /**
   * 最重要的一个方法，它根据读到的歌词内容 进行初始化，比如把歌词一句一句分开并计算好时间
   * 
   * @param content
   *          歌词内容
   */
  private void init(String content) {
    // 如果歌词的内容为空,则后面就不用执行了
    // 直接显示歌曲名就可以了
    if (content == null || content.trim().equals("")) {
      return;
    }
    try {
      BufferedReader br = new BufferedReader(new StringReader(content));
      String temp = null;
      while ((temp = br.readLine()) != null) {
        parseLine(temp.trim());
      }
      appendEndLine();
      br.close();
      // 读进来以后就排序了
      Collections.sort(list, new Comparator<Sentence>() {

        @Override
        public int compare(Sentence o1, Sentence o2) {
          return (int) (o1.getFromTime() - o2.getFromTime());
        }
      });
      int size = list.size();
      for (int i = 0; i < size; i++) {
        Sentence next = null;
        if (i + 1 < size) {
          next = list.get(i + 1);
        }
        Sentence now = list.get(i);
        if (next != null) {
          now.setToTime(next.getFromTime() - 1);
        }
      }
    } catch (Exception ex) {
      Logger.getLogger(Lyric.class.getName()).log(Level.SEVERE, null, ex);
    }
  }

  /**
   * 分析这一行的内容，根据这内容 以及标签的数量生成若干个Sentence对象 当此行中的时间标签分布不在一起时，也要能分析出来 所以更改了一些实现
   * 20080824更新
   * 
   * @param line
   *          这一行
   */
  private void parseLine(String line) {
    if (line.equals("")) {
      return;
    }
    int hasBracket = line.indexOf("[");
    int hasBackBracket = line.indexOf("]");
    if (hasBracket != -1 && hasBackBracket == -1) {
      line = line.replace("[", "");
    } else if (hasBracket == -1 && hasBackBracket != -1) {
      line = line.replace("]", "");
    }

    String s = null, content = null;
    Matcher matcher = pattern.matcher(line);
    int lastIndex = -1;// 最后一个时间标签的下标
    if (matcher.find()) {
      s = matcher.group();
      lastIndex = line.indexOf("]");
      content = line.substring(lastIndex + 1, line.length());

    } else {
      String reg = "[\u4e00-\u9fa5]";
      if (line.matches(".*" + reg + ".*")) {
        lastIndex = line.split(reg)[0].length();
        s = line.substring(0, lastIndex);
        content = line.substring(lastIndex, line.length());
      }
    }
    long t = parseTime(s);
    if (t != -1)
      list.add(new Sentence(content, t));
  }

  /**
   * 把如00:00.00这样的字符串转化成 毫秒数的时间，比如 01:10.34就是一分钟加上10秒再加上340毫秒 也就是返回70340毫秒
   * 
   * @param time
   *          字符串的时间
   * @return 此时间表示的毫秒
   */
  private long parseTime(String time) {
    if (time == null) {
      return -1;
    }

    String[] ss = time.split("\\:|\\.");
    // 如果 是两位以后，就非法了
    if (ss.length < 2) {
      return -1;
    } else if (ss.length == 2) {// 如果正好两位，就算分秒
      try {
        int min = Integer.parseInt(ss[0]);
        int sec = Integer.parseInt(ss[1]);
        if (min < 0 || sec < 0 || sec >= 60) {
          throw new RuntimeException("数字不合法!");
        }
        // System.out.println("time" + (min * 60 + sec) * 1000L);
        return (min * 60 + sec) * 1000L;
      } catch (Exception exe) {
        return -1;
      }
    } else if (ss.length == 3) {// 如果正好三位，就算分秒，十毫秒
      try {
        int min = Integer.parseInt(ss[0]);
        int sec = Integer.parseInt(ss[1]);
        int mm = Integer.parseInt(ss[2]);
        if (min < 0 || sec < 0 || sec >= 60 || mm < 0 || mm > 999) {
          throw new RuntimeException("数字不合法!");
        }
        // System.out.println("time" + (min * 60 + sec) * 1000L + mm *
        // 10);
        return (min * 60 + sec) * 1000L + mm;
      } catch (Exception exe) {
        return -1;
      }
    } else {// 否则也非法
      return -1;
    }
  }

  /**
   * 得到是否初始化完成了
   * 
   * @return 是否完成
   */
  public boolean isInitDone() {
    return initDone;
  }

  /**
   * 得到当前正在播放的那一句的下标 不可能找不到，因为最开头要加一句 自己的句子 ，所以加了以后就不可能找不到了
   * 
   * @return 下标
   */
  int getNowSentenceIndex(long t) {
    for (int i = 0; i < list.size(); i++) {
      if (list.get(i).isInTime(t)) {
        return i;
      }
    }
    if (t <= list.get(0).getFromTime())
      return 0;
    else if (t >= list.get(list.size() - 1).getToTime())
      return list.size() - 1;
    else
      return -1;
  }
}
